﻿namespace MicroCloud.Builders
{
    /// <summary>
    /// 系统构建器
    /// </summary>
    public class MicroCloudBuilder : IMicroCloudBuilder
    {
        //字段
        private readonly List<PackBase> _source;
        private List<PackBase> _packs;

        /// <summary>
        /// 初始化一个系统构建器 <see cref="MicroCloudBuilder"/> 的新实例
        /// </summary>
        /// <param name="services">服务集合</param>
        public MicroCloudBuilder(IServiceCollection services)
        {
            Services = services;
            _source = GetAllPacks();
            _packs = new List<PackBase>();

            //初始化配置信息
            services.InitConfiguration();
            //初始化日志工厂
            services.InitLoggerFactory();
        }

        #region 属性
        /// <summary>
        /// 获取 服务集合
        /// </summary>
        public IServiceCollection Services { get; }

        /// <summary>
        /// 获取 加载的模块集合
        /// </summary>
        public IEnumerable<PackBase> Packs => _packs;

        /// <summary>
        /// 获取 MicroCloud配置信息
        /// </summary>
        public MicroCloudOptions Options { get; private set; }

        #endregion

        #region 方法
        /// <summary>
        /// 加载指定模块
        /// </summary>
        /// <param name="type">模块类型</param>
        /// <returns>系统构建器</returns>
        public IMicroCloudBuilder AddPack(Type type)
        {
            if (!type.IsBaseOn(typeof(PackBase)))
            {
                throw new Exception(I18N.T("要加载的 Pack 类型 {0} 不派生于基类 PackBase", type));
            }

            if (_packs.Any(m => m.GetType() == type))
            {
                return this;
            }

            PackBase[] tmpPacks = new PackBase[_packs.Count];
            _packs.CopyTo(tmpPacks);
            PackBase pack = _source.FirstOrDefault(m => m.GetType() == type) ?? throw new Exception(I18N.T("类型为 {0} 的模块实例无法找到", type.FullName));
            _packs.AddIfNotExist(pack);

            // 添加依赖模块
            Type[] dependTypes = pack.GetDependPackTypes();
            foreach (Type dependType in dependTypes)
            {
                PackBase dependPack = _source.Find(m => m.GetType() == dependType) ?? throw new Exception(I18N.T("加载模块 {0} 时无法找到依赖模块 {1}", pack.GetType().FullName, dependType.FullName));
                _packs.AddIfNotExist(dependPack);
            }

            // 按先层级后顺序的规则进行排序
            _packs = _packs.OrderBy(m => m.Level).ThenBy(m => m.OrderNo).ToList();

            Type logType = typeof(MicroCloudBuilder);
            tmpPacks = _packs.Except(tmpPacks).ToArray();
            foreach (PackBase tmpPack in tmpPacks)
            {
                Type packType = tmpPack.GetType();
                string packName = packType.GetDescription();
                Services.LogInformation($"正在添加模块 {packType.Name}[{packName}] 的服务", logType);
                ServiceDescriptor[] tmp = Services.ToArray();
                AddPack(Services, tmpPack);
                Services.ServiceLogDebug(tmp, packType);
                Services.LogInformation($"模块 {packType.Name}[{packName}] 的服务添加完毕，添加了 {Services.Count - tmp.Length} 个服务。", logType);
            }

            return this;
        }

        /// <summary>
        /// 加载指定模块
        /// </summary>
        /// <typeparam name="TPack">要加载的模块类型</typeparam>
        /// <returns>系统构建器</returns>
        public IMicroCloudBuilder AddPack<TPack>() where TPack : PackBase
        {
            Type type = typeof(TPack);
            return AddPack(type);
        }

        /// <summary>
        /// 加载所有模块(可排除指定类型的模块)
        /// </summary>
        /// <param name="exceptPackTypes">要排除的模块类型</param>
        /// <returns>系统构建器</returns>
        public IMicroCloudBuilder AddPacks(params Type[] exceptPackTypes)
        {
            PackBase[] source = _source.ToArray();
            PackBase[] exceptPacks = source.Where(m => exceptPackTypes.Contains(m.GetType())).ToArray();
            source = source.Except(exceptPacks).ToArray();
            foreach (PackBase pack in source)
            {
                AddPack(pack.GetType());
            }

            return this;
        }

        #endregion

        #region 私有方法
         /// <summary>
        /// 获取所有模块
        /// </summary>
        /// <returns>模块集合</returns>
        private static List<PackBase> GetAllPacks()
        {
            //需要排除已经被继承的Pack实类
            Type[] types = AssemblyManager.FindTypesByBase<PackBase>();
            Type[] packTypes = types.Select(m => m.BaseType).Where(m => m != null && !m.IsAbstract).ToArray();
            packTypes = types.Except(packTypes).ToArray();

            return packTypes.Select(m => (PackBase)Activator.CreateInstance(m)).OrderBy(m => m.Level).ThenBy(m => m.OrderNo).ThenBy(m => m.GetType().FullName).ToList();
        }

        /// <summary>
        /// 添加指定模块
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="pack">模块类型</param>
        /// <returns>服务集合</returns>
        private static IServiceCollection AddPack(IServiceCollection services, PackBase pack)
        {
            Type type = pack.GetType();
            Type serviceType = typeof(PackBase);

            if (type.BaseType?.IsAbstract == false)
            {
                //移除多重继承的模块
                ServiceDescriptor[] descriptors = services.Where(m =>
                    m.Lifetime == ServiceLifetime.Singleton && m.ServiceType == serviceType
                    && m.ImplementationInstance?.GetType() == type.BaseType).ToArray();
                foreach (var descriptor in descriptors)
                {
                    services.Remove(descriptor);
                }
            }

            if (!services.Any(m => m.Lifetime == ServiceLifetime.Singleton && m.ServiceType == serviceType && m.ImplementationInstance?.GetType() == type))
            {
                services.AddSingleton(typeof(PackBase), pack);
                pack.AddServices(services);
            }

            return services;
        }

        #endregion

    }

}
